package vn.edu.ptithcm.pim.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import vn.edu.ptithcm.pim.dom.Task;
import vn.edu.ptithcm.pim.query.TaskQuery;
import vn.edu.ptithcm.pim.util.TaskStatusUtil;

@SuppressWarnings({ "rawtypes" })
public class TaskDao extends HibernateDaoSupport {

	public void save(Task task) {
		try {
			Transaction tx = getSession().beginTransaction();
			getHibernateTemplate().save(task);
			tx.commit();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public void saveOrUpdate(Task task) {
		try {
			Transaction tx = getSession().beginTransaction();
			if (task.getTaskid() != null) {
				getHibernateTemplate().merge(task);
			} else {
				getHibernateTemplate().saveOrUpdate(task);
			}
			tx.commit();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public void lock(Task task) {
		try {
			Transaction tx = getSession().beginTransaction();
			getHibernateTemplate().lock(task, LockMode.NONE);
			tx.commit();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public void delete(Task task) {
		try {
			Transaction tx = getSession().beginTransaction();
			getHibernateTemplate().delete(task);
			tx.commit();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public Task merge(Task task) {
		try {
			return (Task) getHibernateTemplate().merge(task);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public Task findById(java.lang.Long id) {
		try {
			return (Task) getHibernateTemplate().get(Task.class, id);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List findByExample(Task Task) {
		try {
			return getHibernateTemplate().findByExample("Task", Task);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List getAll() {
		try {
			return getHibernateTemplate().loadAll(Task.class);
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List findByProjectId(java.lang.Long projectId) {
		try {
			StringBuilder sql = new StringBuilder();
			sql.append("from Task as task where task.project.projectid ='")
					.append(projectId)
					.append("' order by task.lastchanged desc");
			return getHibernateTemplate().find(sql.toString());
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List getAllTasksHasAttachedfiles(java.lang.Long projectId) {
		try {
			StringBuilder sql = new StringBuilder();
			sql.append("from Task as task where task.project.projectid ='")
					.append(projectId)
					.append("' and task.attachedfiles = true");
			return getHibernateTemplate().find(sql.toString());
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List getAllForCopyProject(java.lang.Long projectId) {
		try {
			StringBuilder sql = new StringBuilder();
			sql.append("from Task as task where task.project.projectid ='")
					.append(projectId)
					.append("' and size(task.tasksForTaskid) = 0 order by task.lastchanged asc");
			return getHibernateTemplate().find(sql.toString());
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List filterByProjectId(java.lang.Long projectId, int max, int offset) {
		try {
			StringBuilder sql = new StringBuilder();
			sql.append("from Task as task where task.project.projectid ='")
					.append(projectId).append("' ")
					.append(" and task.taskStatus.statusid != 8 ")
					.append(" order by task.lastchanged desc ");
			return getSession().createQuery(sql.toString())
					.setFirstResult(offset).setMaxResults(max).list();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public int countFilterByProjectId(java.lang.Long projectId) {
		try {
			StringBuilder sql = new StringBuilder();
			sql.append(
					"select count(*) from Task as task where task.project.projectid ='")
					.append(projectId).append("' ")
					.append(" and task.taskStatus.statusid != 8");
			return Integer.parseInt(getHibernateTemplate().find(sql.toString())
					.get(0).toString());
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public Task findByCode(String code) {
		try {
			String sql = "from Task as task where task.code =? ";
			List result = getHibernateTemplate().find(sql, code);
			return (result != null && result.size() == 1) ? (Task) result
					.get(0) : null;
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public void deleteById(Long id) {
		try {
			Transaction tx = getSession().beginTransaction();
			String sql = "delete from Task where taskid =? ";
			getHibernateTemplate().bulkUpdate(sql, id);
			tx.commit();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public long getMaximumId(Long projectId) {
		try {
			Criteria criteria = getSession().createCriteria(Task.class);
			criteria.createAlias("project", "project");
			criteria.add(Restrictions.eq("project.projectid", projectId));
			criteria.setProjection(Projections.max("taskid"));
			return ((Long) criteria.list().get(0)).intValue();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public int getNumberOfItems(Long projectId) {
		try {
			Criteria criteria = getSession().createCriteria(Task.class);
			criteria.createAlias("project", "project");
			criteria.add(Restrictions.eq("project.projectid", projectId));
			criteria.setProjection(Projections.rowCount());
			return ((Integer) criteria.list().get(0)).intValue();
		} catch (RuntimeException re) {
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	public List<Task> findByQuery(TaskQuery query, Long projectId) {
		try {
			Criteria c = getSession().createCriteria(Task.class);

			String monitoredby = query.getMonitoredby();
			String reporter = query.getReporter();
			String assignedto = query.getAssignedto();
			Long categoryId = query.getCategoryId();
			Long severityId = query.getSeverityId();
			Long priorityId = query.getPriorityId();
			String phase = query.getPhase();
			Date starttime = query.getStarttime();
			Date endtime = query.getEndtime();
			Long hideStatusId = query.getHideStatusId();
			Long showStatusId = query.getShowStatusId();
			Integer itemsPerPage = query.getItemsPerPage();

			c.createAlias("project", "project");
			c.add(Restrictions.eq("project.projectid", projectId));

			if (!monitoredby.isEmpty()) {
				c.add(Restrictions
						.ilike("monitoredby", "%" + monitoredby + "%"));
			}
			if (!assignedto.isEmpty()) {
				c.add(Restrictions.ilike("assignedto", "%" + assignedto + "%"));
			}
			if (!reporter.isEmpty()) {
				c.add(Restrictions.ilike("reporter", "%" + reporter + "%"));
			}
			if (categoryId.intValue() != 0) {
				c.createAlias("taskCategory", "category");
				c.add(Restrictions.eq("category.categoryid", categoryId));
			}
			if (severityId.intValue() != 0) {
				c.createAlias("taskSeverity", "severity");
				c.add(Restrictions.eq("severity.severityid", severityId));
			}
			if (priorityId.intValue() != 0) {
				c.createAlias("taskPriority", "priority");
				c.add(Restrictions.eq("priority.priorityid", priorityId));
			}
			if (!phase.isEmpty()) {
				c.add(Restrictions.ilike("phase", "%" + phase + "%"));
			}
			if (starttime != null) {
				c.add(Restrictions.ge("starttime", starttime));
			}
			if (endtime != null) {
				c.add(Restrictions.le("endtime", endtime));
			}

			if (showStatusId.intValue() != 0 || hideStatusId.intValue() != 0) {
				c.createAlias("taskStatus", "status");
			}
			if (showStatusId.intValue() != 0) {
				c.add(Restrictions.in("status.statusid", TaskStatusUtil
						.getDependencyStatusesForShowing(showStatusId
								.intValue())));
			}
			if (hideStatusId.intValue() != 0) {
				c.add(Restrictions.not(Restrictions.in("status.statusid",
						TaskStatusUtil
								.getDependencyStatusesForHiding(hideStatusId
										.intValue()))));
			}
			if (itemsPerPage != null && itemsPerPage.intValue() > 0) {
				c.setMaxResults(itemsPerPage.intValue());
			}
			c.addOrder(Order.desc("lastchanged"));
			return c.list();
		} catch (RuntimeException re) {
			throw re;
		}
	}
}
